/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.kylingroup.JavaFX.Task;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;


/**
 *
 * @author kylin
 */
public class JavaFxFileTransferWIthProgress2 extends Application{
    
    FileTransfer2 task=null;
    Thread th=null;
    
    @Override
    public void start(Stage primaryStage) throws Exception {

        HBox sourcepane=new HBox();
        Label lsource=new Label("Source:");
        TextField tsource=new TextField();
        Button btnsource=new Button("select");
        btnsource.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                FileChooser filechooser=new FileChooser();
                filechooser.setTitle("Select a source file");
                filechooser.setInitialDirectory(new File(System.getProperty("user.home")));
                File file=filechooser.showOpenDialog(primaryStage);
                if(file!=null){
                    tsource.setText(file.getAbsolutePath());
                }
            }
        });
        sourcepane.getChildren().addAll(lsource,tsource,btnsource);
        
        
        HBox targetpane=new HBox();
        Label ltarget=new Label("Target:");
        TextField ttarget=new TextField();
        Button btntarget=new Button("select");
        btntarget.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                FileChooser filechooser=new FileChooser();
                filechooser.setTitle("Select a target file");
                filechooser.setInitialDirectory(new File(System.getProperty("user.home")));
                File file=filechooser.showSaveDialog(primaryStage);
                if(file!=null){
                    ttarget.setText(file.getAbsolutePath());
                }
            }
        });
        
        targetpane.getChildren().addAll(ltarget,ttarget,btntarget);

        
        HBox buffersizepane=new HBox();
        Label lbuffersize=new Label("set buffersize:");
        TextField tbuffersize=new TextField();
        buffersizepane.getChildren().addAll(lbuffersize,tbuffersize);
        
        HBox sleeppane=new HBox();
        Label lsleep=new Label("Set thread sleep time:");
        TextField tsleep=new TextField();
        sleeppane.getChildren().addAll(lsleep,tsleep);
        
        HBox progresspane=new HBox();
        
        
        TextArea area=new TextArea();
        Button btnStart = new Button("Start to copy");
        btnStart.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                ProgressBar bar = new ProgressBar();
                bar.setProgress(0);
                progresspane.getChildren().add(bar);
                
                
                File source=new File(tsource.getText());
                File target=new File(ttarget.getText());
                int buffersize=Integer.parseInt(tbuffersize.getText());
                int sleep=Integer.parseInt(tsleep.getText());

                task=new FileTransfer2(source,target,buffersize,sleep);
                
                bar.progressProperty().bind(task.progressProperty());

                task.addEventHandler(WorkerStateEvent.WORKER_STATE_SUCCEEDED,
                    new EventHandler<WorkerStateEvent>(){
                    @Override
                    public void handle(WorkerStateEvent event) {
                        HashMap<String,String> info=task.getValue();
                        area.appendText("success\n");
                        area.appendText("source file:"+info.get("sourcefile")+"\n");
                        area.appendText("target file:"+info.get("targetfile")+"\n");
                        area.appendText("size:"+info.get("size")+"\n");
                        area.appendText("buffersize:"+info.get("buffersize")+"\n");
                        area.appendText("time:"+info.get("time")+"\n\n");
                        
                        try {
                            Thread.sleep(2000);
                            
                            if(!progresspane.getChildren().isEmpty()){
                                Collection children=progresspane.getChildren();
                                progresspane.getChildren().removeAll(children);
                            }
                        } catch (InterruptedException ex) {
                            Logger.getLogger(JavaFxFileTransferWIthProgress2.class.getName()).log(Level.SEVERE, null, ex);
                        }

                    } 
                });
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException ex) {
                    Logger.getLogger(JavaFxFileTransferWIthProgress2.class.getName()).log(Level.SEVERE, null, ex);
                }
                th=new Thread(task);
                th.start();
            }
        });
        
        
        Button btnpause=new Button("pause");
        btnpause.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                task.mySuspend();
            }
        });
        Button btnresume=new Button("resume");
        btnresume.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                task.myResume();
            }
        });
        
        VBox vBox = new VBox();
        vBox.setPadding(new Insets(5, 5, 5, 5));
        vBox.setSpacing(5);
        vBox.getChildren().addAll(sourcepane,targetpane,buffersizepane,sleeppane,progresspane,btnStart,btnpause,btnresume,area);
        
        StackPane root = new StackPane();
        root.getChildren().add(vBox);
 
        Scene scene = new Scene(root, 350, 550);
 
        primaryStage.setTitle("file transfer demo");
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    
    public static void main(String[] args) {
        launch(args);
    }

    private void setOnAction(EventHandler<ActionEvent> eventHandler) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }
}

class FileTransfer2 extends Task<HashMap<String,String>>{
    
    private File source=null;
    private File target=null;
    private int sleep=0;
    private int buffersize=0;
    private HashMap<String,String> info=null;
    
    private int STOP = -1;
    private int SUSPEND = 0;
    private int RUNNING = 1;
    private int status = 1;
    
    public FileTransfer2(File source,File target,int buffersize,int sleep){
        this.source=source;
        this.target=target;
        this.buffersize=buffersize;
        this.sleep=sleep;
        info=new HashMap<String,String>();
    }

    @Override
    protected HashMap<String,String> call() throws Exception {
                 
        write();
        //test();
        return info;
    }
    public synchronized void write() throws FileNotFoundException, IOException, InterruptedException{
        
        
        
        FileInputStream in=new FileInputStream(source);
        FileOutputStream out=new FileOutputStream(target);
                
        byte[] buffer=new byte[buffersize];
        long size=source.length();
        long starttime=new Date().getTime();

        int ins=0;
        int rlength=0;
        while((ins= in.read(buffer, 0, buffer.length)) != -1){
            if (status == SUSPEND){
            try{
               // 若线程挂起则阻塞自己
               wait();
            }catch (InterruptedException e){
               System.out.println("线程异常终止...");
            }
         }else{
            out.write(buffer,0,ins);
            rlength+=ins;
            updateProgress(rlength,size);
            Thread.sleep(sleep);
            }
        }
        in.close();
        out.flush();
        out.close();
        
        long endtime=new Date().getTime()-starttime;
        info.put("sourcefile", source.getAbsolutePath());
        info.put("targetfile", target.getAbsolutePath());
        info.put("size", String.valueOf(size));
        info.put("buffersize", String.valueOf(buffersize));
        info.put("time", String.valueOf(endtime));
    }
    public synchronized void test() throws InterruptedException{
        int i=0,max=100;
        
        while (status != STOP){
         // 判断是否挂起
         if (status == SUSPEND){
            try{
               // 若线程挂起则阻塞自己
               wait();
            }catch (InterruptedException e){
               System.out.println("线程异常终止...");
            }
         }else{
            updateProgress(i,max);
            i++;
            try{
               Thread.sleep(sleep);
            }catch (InterruptedException e){
               System.out.println("线程异常终止...");
            }
         }
        }
        
    }
    /**
    * 恢复
    */
   public synchronized void myResume(){
      // 修改状态
      status = RUNNING;
      // 唤醒
      notifyAll();
   }

   /**
    * 挂起
    */
   public void mySuspend(){
      // 修改状态
      status = SUSPEND;
   }

   /**
    * 停止
    */
   public void myStop(){
      // 修改状态
      status = STOP;
   }
}